package cn.net.xyan.easy.spring.web.support;

import cn.net.xyan.easy.spring.core.config.AutoConfigManagerFactory;
import cn.net.xyan.easy.spring.core.config.IAutoConfig;
import cn.net.xyan.easy.spring.core.config.IAutoConfigManager;
import cn.net.xyan.easy.spring.core.utils.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * Created by xiashenpin on 16/1/16.
 */
@HandlesTypes({IWebApplicationInitializer.class, IAutoConfig.class})
public class EasySpringServletContainerInitializer implements ServletContainerInitializer {

    Logger logger = LoggerFactory.getLogger(EasySpringServletContainerInitializer.class);

    @Override
    public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {


        List<? extends Class> annotationClasses = Arrays.asList(IAutoConfig.class, IWebApplicationInitializer.class);

        Map<Class, List<Object>> initializerMap = new HashMap<>();

        //检查容器提供给我们的接口类
        if (webAppInitializerClasses != null) {

            for (Class<?> waiClass : webAppInitializerClasses) {
                // Be defensive: Some servlet containers provide us with invalid classes,
                // no matter what @HandlesTypes says...
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) ){
                    Object newInstance ;
                    try {
                        newInstance = waiClass.newInstance();
                    } catch (Throwable ex) {
                        //throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                        ExceptionUtils.traceError(ex, logger);
                        continue;
                    }

                    for (Class<?> cls : annotationClasses) {
                        List<Object> initializers = initializerMap.get(cls);
                        if (initializers == null) {
                            initializers = new LinkedList<>();
                            initializerMap.put(cls, initializers);
                        }
                        if (cls.isAssignableFrom(waiClass)) {
                            initializers.add(newInstance);

                        }
                    }
                }
            }
        }

        if (initializerMap.get(IWebApplicationInitializer.class).isEmpty()) {
            servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
            return;
        }

        for (Class<?> cls : annotationClasses) {
            AnnotationAwareOrderComparator.sort(initializerMap.get(cls));
        }


        servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializerMap.get(IWebApplicationInitializer.class));

        AutoConfigManagerFactory.doScan = false;//不需要扫描包 容器会告知我们需要的接口类

        IAutoConfigManager manager = AutoConfigManagerFactory.autoConfigManager();

        for (Object obj : initializerMap.get(IAutoConfig.class)) {
            if (obj instanceof IAutoConfig) {
                IAutoConfig initializer = (IAutoConfig) obj;
                initializer.onStartupConfigManager(manager);
            }
        }

        for (Object obj : initializerMap.get(IAutoConfig.class)) {
            if (obj instanceof IAutoConfig) {
                IAutoConfig initializer = (IAutoConfig) obj;
                initializer.afterSetup(manager);
            }
        }

        for (Object obj : initializerMap.get(IWebApplicationInitializer.class)) {
            if (obj instanceof IWebApplicationInitializer) {
                IWebApplicationInitializer initializer = (IWebApplicationInitializer) obj;
                initializer.onStartup(servletContext);
            }
        }

    }
}
